﻿namespace How_toEval;



public record AbstractSyntaxTree
{
    private AbstractSyntaxTree()
    {
    }

    sealed public override string ToString()
    {
        return this switch
        {
            Integer i => i.Value.ToString(),
            Float f => f.Value.ToString(),
            Var v => v.Name,
            BinaryOperateNode b =>
                $"({b.Operator} {b.Left.ToString()} {b.Right.ToString()})",
            Define d => $"(define {d.Name} {d.Value.ToString()})",
            Call c => $"({c.Called} {String.Join(' ', c.Arguments)})",
            Function f => $"(lambda{(f.TypeName == "" ? "" : $" : {f.TypeName}")} ({String.Join(
                ' ',
                f.Params
                 .Select(p => p.Item2 == "" ?
                        p.Item1 : $"{p.Item1} : {p.Item2}")
            )}) {f.Body.ToString()})",
            Group g => $"(begin {String.Join(' ', g.Leaves)})",
            AnnotatedExpression a => $"{a.Expression.ToString()} : {a.Annotation}",
            _ => throw new Exception("Unexpected AST type")
        };
    }

    sealed public record Integer(int Value) : AbstractSyntaxTree;

    sealed public record Float(double Value) : AbstractSyntaxTree;

    sealed public record BinaryOperateNode(AbstractSyntaxTree Left, AbstractSyntaxTree Right, string Operator) : AbstractSyntaxTree;

    sealed public record Define(string Type, string Name, AbstractSyntaxTree Value) : AbstractSyntaxTree;

    sealed public record Group(List<AbstractSyntaxTree> Leaves) : AbstractSyntaxTree;

    sealed public record Var(string Name) : AbstractSyntaxTree;

    sealed public record Function(AbstractSyntaxTree Body, List<(string, string)> Params, string TypeName = "") : AbstractSyntaxTree;

    sealed public record Call(AbstractSyntaxTree Called, List<AbstractSyntaxTree> Arguments, string TypeName = "") : AbstractSyntaxTree;

    sealed public record AnnotatedExpression(AbstractSyntaxTree Expression, string Annotation) : AbstractSyntaxTree;
}


